package com.sychip.fhc.app.data.repo.impl


import com.sychip.fhc.app.data.repo.WsnDeviceRepo
import com.sychip.fhc.app.data.source.convert.toDto
import com.sychip.fhc.app.data.source.convert.toEntity
import com.sychip.fhc.app.data.source.dao.WsnDeviceDao
import com.sychip.fhc.app.data.source.dto.WsnDeviceDto
import com.sychip.fhc.di.IoDispatcher
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.withContext
import javax.inject.Inject
import javax.inject.Singleton


@Singleton
class WsnDeviceRepoImpl @Inject constructor(
    private val wsnDeviceDao: WsnDeviceDao,
    @IoDispatcher private val dispatcher: CoroutineDispatcher
) : WsnDeviceRepo {
    override fun getAllWsnDevices(usbId: String): Flow<List<WsnDeviceDto>> = flow {
        val devList =wsnDeviceDao.getAll(usbId).toDto()
        emit(devList)
    }

    override fun observeAllWsnDevices(usbId: String): Flow<List<WsnDeviceDto>> {
       return wsnDeviceDao.observeAll(usbId).map { it.toDto() }
    }

    override fun createWsnDevice(usbId: String, devId: String, devType: String, lastData: String, offsetX: Float, offsetY: Float): Flow<WsnDeviceDto> = flow {
        val task = WsnDeviceDto(
            devId = devId,
            offsetX = offsetX,
            offsetY = offsetY,
            lastData =  lastData,
            devType = devType,
        )
        wsnDeviceDao.upsert(task.toEntity())
        emit(task)
    }

    override suspend fun updateOffset(usbId: String, devId: String, offsetX: Float, offsetY: Float):WsnDeviceDto{
//        val task = getWsnDevice(usbId, devId)?.copy(
//            offsetX = offsetX,
//            offsetY = offsetY,
//        ) ?: throw Exception("WsnDevice (id $devId) not found")
        var task = getWsnDevice(usbId, devId)?.copy(
            offsetX = offsetX,
            offsetY = offsetY,
        )
        if (task == null)  task = WsnDeviceDto(
            devId = devId,
            offsetX = offsetX,
            offsetY = offsetY,
        )
        wsnDeviceDao.upsert(task.toEntity())
        return task
    }

    override suspend fun updateLastData(usbId: String, devId: String, lastData: String):WsnDeviceDto {
        val task = getWsnDevice(usbId, devId)?.copy(
            lastData =  lastData,
        ) ?: throw Exception("WsnDevice (id $devId) not found")

        wsnDeviceDao.upsert(task.toEntity())
        return task

    }


    override suspend fun getWsnDevices(usbId: String): List<WsnDeviceDto> {
        return withContext(dispatcher) {
            wsnDeviceDao.getAll(usbId).toDto()
        }
    }

    override fun getWsnDevicesStream(usbId: String): Flow<List<WsnDeviceDto>> {
        return wsnDeviceDao.observeAll(usbId).map { tasks ->
            withContext(dispatcher) {
                tasks.toDto()
            }
        }
    }


    override fun getWsnDeviceStream(usbId: String, devId: String): Flow<WsnDeviceDto?> {
        return wsnDeviceDao.observeById(usbId, devId).map { it.toDto() }
    }

    override suspend fun getWsnDevice(usbId: String, devId: String): WsnDeviceDto? {
        return wsnDeviceDao.getById(usbId, devId)?.toDto()
    }


    override suspend fun deleteAll(usbId: String) {
        wsnDeviceDao.deleteAll(usbId)
    }

    override suspend fun deleteWsnDevice(usbId: String, devId: String):Int {
        return wsnDeviceDao.deleteById(usbId, devId)
    }

}
